# -*- coding: utf-8 -*-

"""
通用功能。
"""

import os
import subprocess
import tempfile
import traceback
from functools import wraps

# 3-party
import yaml

from .log import get_logger


logger = get_logger(__name__, "INFO")


def get_agent_root_path(isWindows):
    """获取Agent根路径。"""
    windows = "c:\\easyops\\agent"
    linux = "/usr/local/easyops/agent"
    
    return windows if isWindows else linux


def get_availabel_server_ip(agentPath):
    """从Agent配置文件获取平台IP地址。"""
    confFile = os.path.join(agentPath, "easyAgent", "conf", "conf.yaml")
    
    with open(confFile, "r") as f:
        config = yaml.load(f)
        hosts = config["command"]["server_groups"][0]["hosts"][0]["ip"].split(",")
    
    # TODO：找到一个可连接的地址并返回
    return hosts[0]


def func_err_handle(default, msg):
    """函数产生异常时，输出错误日志并返回一个默认值。
    参数：
    - default：发生异常时返回的默认值；
    - msg：错误消息；
    """
    def decorator(func):
        # 抵消包装器对被包装函数的污染
        @wraps(func)
        def handler(*args, **kwargs):
            try:
                return func(*args, **kwargs)
            except:
                logger.error(u"%s：%s" % (msg, traceback.format_exc()))
                return default
        return handler
    return decorator


# 使用Py3在操作系统中执行命令，check_output方法在Py3中支持timeout参数
def single_command3(command, stderr=subprocess.STDOUT, shell=True):
    """在操作系统中执行命令。"""
    try:
        # 默认使用nobody用户执行命令，无需提权
        #user = getpass.getuser()
        #if user != "root" and not re.match("\.|source|export", command):
        #    command = "sudo " + command
        result = subprocess.check_output(command, stderr=stderr, shell=shell)
        return True, result.rstrip(os.linesep)
    except subprocess.CalledProcessError as e:
        logger.error(u"命令执行失败：%s" % traceback.format_exc())
        result = "%s: %s" % (e, e.output)
        result = result.rstrip(os.linesep)
        logger.error(u"失败原因：%s" % result)
        return False, result


# 使用Py2在操作系统中执行命令，使用tempfile优化内存使用
# 某些场景下timeout异常导致命令失败，例如执行snmpwalk时
def single_command2(command, shell=True, close_fds=False, stdin=None, **kwargs):
    """在操作系统中执行命令。
    参考：https://docs.python.org/zh-cn/2.7/library/subprocess.html

    参数：
    - command：在shell为True时为字符序列或字符串，为False时只能为字符序列；
    - shell：是否启用shell特性，启用将增加安全性；
    - 
    """
    env = dict(kwargs.pop("env", {})) if kwargs.get("env") else os.environ.copy()

    # 使用tempfile生成临时文件代替内存，解决大量数据下的内存占用问题
    # TemporaryFile方法创建不可见文件，使用后被立即删除
    with tempfile.TemporaryFile() as stdoutF, tempfile.TemporaryFile() as stderrF:
        proc = subprocess.Popen(
            command,
            close_fds=close_fds,
            shell=shell,
            stdin=stdin,
            stdout=stdoutF,
            stderr=stderrF,
            env=env,
            **kwargs)
        proc.wait()
        stderrF.seek(0)
        err = stderrF.read().rstrip(os.linesep)

        stdoutF.seek(0)
        out = stdoutF.read().rstrip(os.linesep)
    
    if proc.returncode == 0:
        return True, out
    else:
        logger.error(u"命令执行失败，返回码：%s，失败原因：%s" % (proc.returncode, err))
        return False, err
    